<?php
namespace app\api\service;
use Des3\DES3;
use think\Controller;
use think\Db;
use think\Exception;
use think\Loader;
use think\Session;
use Jssdk\JSSDK;
use WxpayAPI\JsApiPay;
use WxpayAPI\WxPayApi;
use WxpayAPI\WxPayUnifiedOrder;

/**
 * Created by PhpStorm.
 * User: Administrator
 * Date: 2017/5/26 0026
 * Time: 15:40
 */

class Pay extends Controller {

    /**
     * 获取支付数据
     * @param $param
     * @return mixed
     */
    public static function get_pay_info($param) {
        try {
            $model = $param['model'];
            if (!in_array($model, ['activity', 'order'])) {
                throw new \Exception('支付模型错误');
            }

            $model_data = model($model)->get(['id' => $param['id'], 'member_id' => $param['member_id']]);
            if (!$model_data) {
                throw new \Exception('订单不存在！');
            }
            $price = $model_data->price;
            if ($model == 'activity' && $model_data->product_id > 0) { // 如果活动有赞助商品，需要支付赞助商品押金
                $price += $model_data->product->price;
            }

            $data['price'] = $price;
            $data['order_sn'] = $model_data->order_sn;
            $data['order_id'] = $model_data->id;
            $data['model'] = $model;
            $data['integral'] = $model_data->orderMember->integral;

            return api_return(200, $data);
        } catch (\Exception $e) {
            return api_return(0, [], $e->getMessage());
        }
    }

    /**
     * 检查支付密码是否正确
     * @param $param
     * @return array
     */
    public static function check_safe_password($param) {
        try {
            $member_id = $param['member_id'];
            // 解密数据
            $des = new DES3();
            $safe_password = $des->decrypt($param['safe_password']);

            $time = strtotime(date('Y-m-d'));
            $error_count = model('safe_password_error_log')->where('member_id', $member_id)->where('create_time', '> time', $time)->count();
            if ($error_count >= 3) {
                throw new \Exception('安全密码已锁定，请明天再试');
            }

            $member = model('member')->get(['id' => $member_id]);
            if (!$member['safe_password']) {
                throw new \Exception('未设置支付密码');
            }
            $safe_password .= $member['salt'];
            if (md5($safe_password) != $member['safe_password']) {
                // 增加错误记录
                $error_data = ['member_id' => $member_id];
                model('safe_password_error_log')->save($error_data);
                if ($error_count == 0) {
                    throw new \Exception('支付密码第一次验证错误,还有两次机会');
                }
                if ($error_count == 1) { // 第二次错误
                    throw new \Exception('支付密码第二次验证错误，还有一次机会');
                }
                if ($error_count == 2) { // 第三次错误
                    throw new \Exception('支付密码第三次验证错误，安全密码被锁定');
                }
                throw new \Exception('安全密码已锁定，请明天再试');
            }
            // 验证成功 删除当天错误记录
            model('safe_password_error_log')->where('member_id', $member_id)->delete();
            return api_return(200, []);
        } catch (\Exception $e) {
            return api_return(0, [], $e->getMessage());
        }
    }

    /**
     * 检查是否设置支付密码
     * @param $param
     * @return array
     */
    public static function is_set_safe_password($param) {
        try {
            $member_safe_password = model('member')->where('id', $param['member_id'])->value('safe_password');
            if (!$member_safe_password) {
                throw new \Exception('未设置安全密码');
            }
            return api_return(200, []);
        } catch (\Exception $e) {
            return api_return(0, [], $e->getMessage());
        }
    }

    /**
     * 微信web端支付信息
     * @param $order_sn
     * @param $order_price
     * @param $attach
     * @return array
     */
    public static function wx_web_pay($order_sn, $order_price, $attach)
    {
        try
        {
            $notify_url = request()->domain() . "/index/pay/notify";
            //throw new \Exception($notify_url);
            // ①、获取用户openid
            $tools = new JsApiPay();
            $openId = $tools->GetOpenid($order_sn);
            // ②、统一下单
            $input = new WxPayUnifiedOrder();
            $input->SetBody('就行天下订单支付');
            $input->SetAttach($attach); // 自定义参数 原样返回
            // $input->SetOut_trade_no(WxPayConfig::MCHID.date("YmdHis"));
            $input->SetOut_trade_no($order_sn);
            // $input->SetTotal_fee(1);
            if ($order_price <= 0) {
                throw new \Exception("支付金额必须大于0");
            }
            $input->SetTotal_fee($order_price * 100);
            $input->SetTime_start(date("YmdHis"));
            $input->SetTime_expire(date("YmdHis", time() + 600));
            $input->SetGoods_tag("");
            $input->SetNotify_url($notify_url);
            $input->SetTrade_type("JSAPI");
            $input->SetOpenid($openId);
            $order = WxPayApi::unifiedOrder($input);
            // exit(json_encode($order));
            // echo '<font color="#f00"><b>统一下单支付单信息</b></font><br/>';
            // $this->printf_info($order);
            $jsApiParameters = $tools->GetJsApiParameters($order);

            // 获取共享收货地址js函数参数
            $editAddress = $tools->GetEditAddressParameters();

            // ③、在支持成功回调通知中处理成功之后的事宜，见 notify.php
            /**
             * 注意： 1、当你的回调地址不可访问的时候，回调通知会失败，可以通过查询订单来确认支付是否成功 2、jsapi支付时需要填入用户openid，WxPay.JsApiPay.php中有获取openid流程 （文档可以参考微信公众平台“网页授权接口”， 参考http://mp.weixin.qq.com/wiki/17/c0f37d5704f0b64713d5d2c37b468d75.html）
             */

            return ['code' => 200,'jsApiParameters' => $jsApiParameters,'editAddress' => $editAddress];
        }
        catch (\Exception $e)
        {
            return ['code' => 400,'msg' => $e->getMessage()];
        }
    }

    /**
     * 微信app端支付信息
     * @param
     * $param
     * @return array
     */
    public static function wx_app_pay($param) {
        try {
            $order = model($param['model'])->get(['id' => $param['order_id'], 'member_id' => $param['member_id']]);
            if (!$order) {
                throw new \Exception("订单不存在");
            }
            $price = $order->price;
            if ($param['model'] == 'activity' && $order->product_id > 0) {
                // 如果是活动并且有赞助商品,支付金额需要加上商品金额
                $price += $order->product->price;
            }
            // 测试阶段  支付金额设为0.01
//            $price = 0.01;

            /**
             * 微信支付附加数据
             */
            $des3 = new DES3();
            $attach['sign'] = $des3->encrypt('jxtx.com');

            $notify_url = request()->domain() . "/index/pay/app_notify";

            Loader::import('WxpayAPPAPI.WxPayData');
            $input = new \WxPayUnifiedOrder();
            $input->SetBody("就行天下订单支付");
            $input->SetAttach(json_encode($attach)); // 商家数据包
            // $input->SetOut_trade_no(\WxPayConfig::MCHID.date("YmdHis"));//商户订单号
            $input->SetOut_trade_no($order->order_sn);
            $input->SetTotal_fee($price * 100); // 金额
            // $input->SetTotal_fee(1); //金额
//            $input->SetTime_start(date("YmdHis"));
//            $input->SetTime_expire(date("YmdHis", time() + 600));
            // $input->SetGoods_tag("test");
            $input->SetNotify_url($notify_url);
            $input->SetTrade_type("APP");

            // $input->SetOpenid($openId);
            Loader::import('WxpayAPPAPI.WxPayApi');
            $result = \WxPayApi::unifiedOrder($input);

            if(!array_key_exists("appid", $result)
                || !array_key_exists("prepay_id", $result)
                || $result['prepay_id'] == "")
            {
                throw new \WxPayException("参数错误:".json_encode($result) );
            }

            // 生成APP接口需要的数据
            $app_data = [
                'appid' => $result['appid'],
                'partnerid' => $result['mch_id'],
                'prepayid' => $result['prepay_id'],
                'package' => 'Sign=WXPay',
                'noncestr' => \WxPayApi::getNonceStr(),
                'timestamp' => time(),
            ];
            //签名步骤一：按字典序排序参数,并将参数按格式转化为字符串
            ksort($app_data);
            $buff = "";
            foreach ($app_data as $k => $v)
            {
                if($k != "sign" && $v != "" && !is_array($v)){
                    $buff .= $k . "=" . $v . "&";
                }
            }
            $buff = trim($buff, "&");

            //签名步骤二：在string后加入KEY
            $string = $buff . "&key=".\WxPayConfig::KEY;
            //签名步骤三：MD5加密
            $string = md5($string);
            //签名步骤四：所有字符转为大写
            $sign = strtoupper($string);

            $app_data['sign'] = $sign;


            // ③、在支持成功回调通知中处理成功之后的事宜，见 notify.php
            /**
             * 注意： 1、当你的回调地址不可访问的时候，回调通知会失败，可以通过查询订单来确认支付是否成功
             * 2、jsapi支付时需要填入用户openid，WxPay.JsApiPay.php中有获取openid流程 （文档可以参考微信公众平台“网页授权接口”， 参考http://mp.weixin.qq.com/wiki/17/c0f37d5704f0b64713d5d2c37b468d75.html）
             */

            return api_return(200, $app_data);
        }
        catch (\Exception $e)
        {
            return ['code' => 400,'msg' => $e->getMessage()];
        }
    }


    /**
     * 支付宝app端支付信息
     * @param
     * $param
     * @return array
     */
    public static function ali_app_pay($param) {
        try {
            $order = model($param['model'])->get(['id' => $param['order_id'], 'member_id' => $param['member_id']]);
            if (!$order) {
                throw new \Exception("订单不存在");
            }
            $price = $order->price;
            if ($param['model'] == 'activity' && $order->product_id > 0) {
                // 如果是活动并且有赞助商品,支付金额需要加上商品金额
                $price += $order->product->price;
            }
            // 测试阶段  支付金额设为0.01
//            $price = 0.01;
//            Loader::import('Alipay.aop.AopClient');
            Loader::import('Alipay.AopSdk');
            $alipay_config = config('alipay');
            $c = new \AopClient;
            $c->gatewayUrl = "https://openapi.alipay.com/gateway.do";
            $c->appId = $alipay_config['appId'];
            // 开发者私钥
            $c->rsaPrivateKey = $alipay_config['rsaPrivateKey'];
            $c->format = "json";
            $c->charset= "utf-8";
            $c->signType= "RSA2";
            // 支付宝公钥
            $c->alipayrsaPublicKey = $alipay_config['alipayrsaPublicKey'];
//实例化具体API对应的request类,类名称和接口名称对应
            $request = new \AlipayTradeAppPayRequest();
//SDK已经封装掉了公共参数，这里只需要传入业务参数
//此次只是参数展示，未进行字符串转义，实际情况下请转义
            $bizContent = "{" .
                "    \"subject\":\"就行天下订单支付\"," .
                "    \"out_trade_no\":\"$order->order_sn\"," .
                "    \"total_amount\":\"$price\"," .
                "    \"product_code\":\"QUICK_MSECURITY_PAY\"" .
                " }";

            $request->setBizContent($bizContent);
            $request->setNotifyUrl(request()->domain() . '/index/pay/ali_notify');
            $response= $c->sdkExecute($request);

            return api_return(200, $response);
        }
        catch (\Exception $e)
        {
            return ['code' => 400,'msg' => $e->getMessage()];
        }
    }

    /**
     * 微信app端支付信息
     * @param
     * $param
     * @return array
     */
    public static function wx_app_pay_test($param) {
        try {
            // 测试阶段  支付金额设为0.01
            $price = $param['money'];

            /**
             * 微信支付附加数据
             */
            $des3 = new DES3();
            $attach['sign'] = $des3->encrypt('jxtx.com');

            $notify_url = request()->domain() . "/index/pay/notify";

            Loader::import('WxpayAPPAPI.WxPayData');
            $input = new \WxPayUnifiedOrder();
            $input->SetBody("就行天下订单支付");
            $input->SetAttach(json_encode($attach)); // 商家数据包
            // $input->SetOut_trade_no(\WxPayConfig::MCHID.date("YmdHis"));//商户订单号
            $input->SetOut_trade_no('TOUR' . date('YmdHis') . rand(1000, 9999));
            $input->SetTotal_fee($price * 100); // 金额
            // $input->SetTotal_fee(1); //金额
            $input->SetTime_start(date("YmdHis"));
            $input->SetTime_expire(date("YmdHis", time() + 600));
            // $input->SetGoods_tag("test");
            $input->SetNotify_url($notify_url);
            $input->SetTrade_type("APP");

            // $input->SetOpenid($openId);
            Loader::import('WxpayAPPAPI.WxPayApi');
            $result = \WxPayApi::unifiedOrder($input);

            // ③、在支持成功回调通知中处理成功之后的事宜，见 notify.php
            /**
             * 注意： 1、当你的回调地址不可访问的时候，回调通知会失败，可以通过查询订单来确认支付是否成功
             * 2、jsapi支付时需要填入用户openid，WxPay.JsApiPay.php中有获取openid流程 （文档可以参考微信公众平台“网页授权接口”， 参考http://mp.weixin.qq.com/wiki/17/c0f37d5704f0b64713d5d2c37b468d75.html）
             */

            return api_return(200, $result);
        }
        catch (\Exception $e)
        {
            return ['code' => 400,'msg' => $e->getMessage()];
        }
    }

    /**
     * 微信支付回调
     * @param $order_price
     * @param $order_sn
     * @param $trade_no
     * @param $pay_type
     * @param $pay_desc
     * @return bool
     */
    public static function pay_notify($order_price, $order_sn, $trade_no, $pay_type, $pay_desc)
    {
        Db::startTrans();
        try {
            $order_data = [
                'pay_type' => $pay_type,
                'pay_sn' => $trade_no,
                'pay_time' => time()
            ];
            $order_model = substr($order_sn, 0, 2);
            if ($order_model == 'HD') {
                // + ------  活动订单 ------ + //
                $order = model('activity')->get(['order_sn' => $order_sn]);
                if ($order['status'] != 1) {
                    add_error_log('订单状态为' . $order['status'] . ',不是待付款状态', $order->order_sn);
                    return false; // 订单不是待付款状态
                }

                $price = $order->price;
                if ($order->product_id > 0) {
                    // 有赞助商品的话支付金额为活动保证金+赞助商品押金
                    $price += $order->product->price;
                }

                if ($price != $order_price && $order_price != 0.01) {
                    add_error_log('活动订单实际支付金额为：' . $order_price . ',与待支付金额不相等', $order->order_sn);
                    return false; // 支付金额不对
                }

                // 补充订单数据
                $order_data['status'] = 2;
                model('activity')->save($order_data, ['order_sn' => $order_sn]);
                // 增加用户支付账单
                MemberBill::add_member_bill($order->member_id, $order_price, '活动订单支付', 1, $order_sn, 'activity', $pay_desc, 3);
            } else if ($order_model == 'ZB') {
                // + ------  直播充值订单 ------ + //
                $order = model('order_zb')->get(['order_sn' => $order_sn]);
                if ($order['status'] != 1) {
                    add_error_log('订单状态为' . $order['status'] . ',不是待付款状态', $order->order_sn);
                    return false; // 订单不是待付款状态
                }

                if ($order->price != $order_price && $order_price != 0.01) {
                    add_error_log('直播订单实际支付金额为：' . $order_price . ',与待支付金额不相等', $order->order_sn);
                    return false; // 支付金额不对
                }

                // 补充订单数据
                $order_data['status'] = 2;
                model('order_zb')->save($order_data, ['order_sn' => $order_sn]);

                // 充值成功 添加赠送记录(评价)
                $comment_data = [
                    'openid' => $order->openid,
                    'nickname' => $order->nickname,
                    'headimgurl' => $order->headimgurl,
                    'video_id' => $order->video_id,
                    'num' => $order->num,
                    'content' => '赠送' . $order->num . '元宝',
                ];
                model('zb_comment')->save($comment_data);

                // 增加用户账单
                //MemberBill::add_member_bill($order->member_id, $order_price, '元宝充值', 2, $order_sn, 'order_zb', $pay_desc, 4);
            } else if ($order_model == 'JX') {
                // + ------  就行订单 ------ + //
                $order = model('order')->get(['order_sn' => $order_sn]);
                file_put_contents(RUNTIME_PATH  . 'NotifyProcess.txt',json_encode($order) . " \n\n ", FILE_APPEND);
                if (($order->type == 2 && $order->status != 1) || ($order->type == 1 && $order->status != 3)) {
                    file_put_contents(RUNTIME_PATH  . 'NotifyProcess.txt','订单类型为' . $order['type'] . '状态为' . $order['status'] . ',不是待付款状态' . " \n\n ", FILE_APPEND);
                    add_error_log('订单类型为' . $order['type'] . '状态为' . $order['status'] . ',不是待付款状态', $order->order_sn);
                    return false; // 订单不是待付款状态
                }

                if ($order->price != $order_price && $order_price != 0.01) {
                    file_put_contents(RUNTIME_PATH  . 'NotifyProcess.txt','订单实际支付金额为：' . $order_price . ',与待支付金额不相等' . " \n\n ", FILE_APPEND);
                    add_error_log('订单实际支付金额为：' . $order_price . ',与待支付金额不相等', $order->order_sn);
                    return false; // 支付金额不对
                }

                // 补充订单数据
                $order_data['status'] = 4;
                file_put_contents(RUNTIME_PATH  . 'NotifyProcess.txt',json_encode($order_data) . " \n\n ", FILE_APPEND);
                model('order')->save($order_data, ['order_sn' => $order_sn]);

                // 增加用户账单
                MemberBill::add_member_bill($order->member_id, $order_price, '订单支付', 1, $order_sn, 'order', $pay_desc, 3);
            }
            // 提交事务
            Db::commit();
            return true;
        } catch (\Exception $e) {
            // 回滚事务
            Db::rollback();
            file_put_contents(RUNTIME_PATH  . 'NotifyProcess.txt', $e->getMessage() . "5 \n\n ", FILE_APPEND);
            return false;
        }
    }

    /**
     * 余额支付
     * @param $param
     * @return array
     */
    public static function instation_pay($param) {
        Db::startTrans();
        try {
            $model = $param['model'];
            $order = model($model)->get(['id' => $param['order_id'], 'member_id' => $param['member_id']]);
            if ($order) {
                $price = $order->price;
                // 检查余额是否充足
                if ($order->orderMember->money < $price) {
                    throw new \Exception('账户余额不足');
                }

                // 余额充足 扣除余额
                model('member')->where(['id' => $param['member_id']])->setDec('money', $price);

                if ($model == 'order') {
                    $order_sn = $order->order_sn;
                    $save_data = ['pay_type' => '余额支付', 'pay_time' => time(), 'status' => 4];
                    model('order')->save($save_data, ['id' => $order->id]);
                } else {
                    throw new \Exception('订单类型异常');
                }
                MemberBill::add_member_bill($param['member_id'], $price, '订单支付', 1, $order_sn, $model,  '余额支付', 1);
            } else {
                throw new \Exception('订单不存在');
            }

//            if ($model == 'order') {
//                // 订单支付成功 - 通知量体师
//                $param = [
//                    'order_id' => $order->id
//                ];
//                //\app\api\service\PatternMaster::inform($param);
//            }

            Db::commit();
            return api_return(200, []);
        } catch (\Exception $e) {
            Db::rollback();
            return api_return(0, [], $e->getMessage());
        }
    }
}